In this assignment you will develop your initial concept note into a draft of a full project proposal. Treat this assignment as a “dry run” for developing a proposal for a grant or fellowship application, or for your Ph.D. prospectus.

Your proposal should include at least the following sections and information.

Front matter: Descriptive title, your name, date, reference to “SYS 7030 Time Series Analysis & Forecasting, Fall 2020”.

Abstract: A very brief summary of the project.

1 Introduction

Give a narrative description of the problem you are addressing, and the methods you will use to address it. Provide context:

This work addresses the question: Why do people not use probabilistic forecasts for decision-making (National Research Council 2007)?

2 The data and the data-generating process

Describe the data set you will be analyzing, and where it comes from, how it was generated and collected. Identify the source of the data. Give a narrative description of the data-generating process: this piece is critical.

Since these will be time series data: identify the frequency of the data series (e.g., hourly, monthly), and the period of record.

esales <- dbGetQuery(db,'SELECT * from eia_elec_sales_va_all_m') # SQL code to retrieve data from a table in the remote database
# str(esales)
esales <- as_tibble(esales) # Convert dataframe to a 'tibble' for tidyverse work
# str(esales)
# Reference: https://arrow.apache.org/docs/r/
# if(!('arrow' %in% installed.packages())) install.packages('arrow')
library(arrow)
write_feather(esales, "esales.feather")
# Close connection -- this is good practice
dbDisconnect(db)
dbUnloadDriver(db_driver)

3 Exploratory data analysis

library(arrow)

Attaching package: 'arrow'
The following object is masked from 'package:utils':

    timestamp
esales <- read_feather("esales.feather")

str(esales)
tibble [233 × 4] (S3: tbl_df/tbl/data.frame)
 $ value: num [1:233] 8282 7839 8889 9368 9209 ...
 $ date : Date[1:233], format: "2020-05-01" "2020-04-01" ...
 $ year : int [1:233] 2020 2020 2020 2020 2020 2019 2019 2019 2019 2019 ...
 $ month: int [1:233] 5 4 3 2 1 12 11 10 9 8 ...

3.1 Provide a brief example of the data, showing how they are structured.

print(esales)
# A tibble: 233 x 4
    value date        year month
    <dbl> <date>     <int> <int>
 1  8282. 2020-05-01  2020     5
 2  7839. 2020-04-01  2020     4
 3  8889. 2020-03-01  2020     3
 4  9368. 2020-02-01  2020     2
 5  9209. 2020-01-01  2020     1
 6 10038. 2019-12-01  2019    12
 7  9291. 2019-11-01  2019    11
 8  8757. 2019-10-01  2019    10
 9  9874. 2019-09-01  2019     9
10 10912. 2019-08-01  2019     8
# … with 223 more rows
# References: https://www.tidyverse.org/, https://dplyr.tidyverse.org/

esales %>%
  filter(year == 2019) %>%
  filter(value > 9000) %>%
  print()
# A tibble: 10 x 4
    value date        year month
    <dbl> <date>     <int> <int>
 1 10038. 2019-12-01  2019    12
 2  9291. 2019-11-01  2019    11
 3  9874. 2019-09-01  2019     9
 4 10912. 2019-08-01  2019     8
 5 11527. 2019-07-01  2019     7
 6  9903. 2019-06-01  2019     6
 7  9147. 2019-05-01  2019     5
 8  9466. 2019-03-01  2019     3
 9  9148. 2019-02-01  2019     2
10 10925. 2019-01-01  2019     1
esales %>%
  group_by(month) %>%
  summarise(mean = mean(value)) -> mean_esales_by_month
`summarise()` ungrouping output (override with `.groups` argument)
esales %>%
  mutate(sales_TWh = value/1000) %>%
  select(-value)
# filter(data object, condition) : syntax for filter() command

3.2 Plot the time series.

#Reference: https://ggplot2.tidyverse.org/

ggplot(data=esales, aes(x=date,y=value)) + 
  geom_line() + xlab("Year") + ylab("Virginia monthly total electricity sales (GWh)")

# install.packages("tsibble")
library(tsibble) # Reference: https://tsibble.tidyverts.org/articles/intro-tsibble.html

Attaching package: 'tsibble'
The following object is masked from 'package:lubridate':

    interval
esales %>% as_tsibble(index = date) -> esales_tbl_ts

print(esales_tbl_ts)
# A tsibble: 233 x 4 [1D]
   value date        year month
   <dbl> <date>     <int> <int>
 1 9576. 2001-01-01  2001     1
 2 7820. 2001-02-01  2001     2
 3 8070. 2001-03-01  2001     3
 4 7153. 2001-04-01  2001     4
 5 7224. 2001-05-01  2001     5
 6 8264. 2001-06-01  2001     6
 7 8896. 2001-07-01  2001     7
 8 9404. 2001-08-01  2001     8
 9 7753. 2001-09-01  2001     9
10 7272. 2001-10-01  2001    10
# … with 223 more rows
library(lubridate) # Make it easy to deal with dates

esales_tbl_ts %>% filter(month==3)
esales_tbl_ts %>% filter(month(date)==3)
esales_tbl_ts %>%
  select(date, sales_GWh = value) -> elsales_tbl_ts

print(elsales_tbl_ts)
# A tsibble: 233 x 2 [1D]
   date       sales_GWh
   <date>         <dbl>
 1 2001-01-01     9576.
 2 2001-02-01     7820.
 3 2001-03-01     8070.
 4 2001-04-01     7153.
 5 2001-05-01     7224.
 6 2001-06-01     8264.
 7 2001-07-01     8896.
 8 2001-08-01     9404.
 9 2001-09-01     7753.
10 2001-10-01     7272.
# … with 223 more rows

3.3 Perform and report the results of other exploratory data analysis

hist(elsales_tbl_ts$sales_GWh, breaks=40)

# install.packages("feasts"), Reference: https://feasts.tidyverts.org/
library(feasts)
Loading required package: fabletools
elsales_tbl_ts %>% 
  mutate(Month = yearmonth(date)) %>% 
  as_tsibble(index = Month) -> vaelsales_tbl_ts


vaelsales_tbl_ts %>% gg_season(sales_GWh, labels = "both") + ylab("Virginia electricity sales (GWh)")

# install.packages('tsibbledata')
library(tsibbledata)

aus_production
aus_production %>% gg_season(Electricity)

aus_production %>% gg_season(Beer)

vaelsales_tbl_ts %>% 
  gg_subseries(sales_GWh)

# aus_production %>% gg_subseries(Beer)
vaelsales_tbl_ts  %>% filter(month(Month) %in% c(3,6,9,12)) %>% gg_lag(sales_GWh, lags = 1:2)

vaelsales_tbl_ts  %>% filter(month(Month) == 1) %>% gg_lag(sales_GWh, lags = 1:2)

vaelsales_tbl_ts %>% ACF(sales_GWh) %>% autoplot()

# if(!('fpp3' %in% installed.packages())) install.packages('fpp3')
library(fpp3)
── Attaching packages ────────────────────────────────────────────── fpp3 0.3 ──
✓ fable 0.2.1     
── Conflicts ───────────────────────────────────────────────── fpp3_conflicts ──
x lubridate::date()   masks base::date()
x dplyr::filter()     masks stats::filter()
x tsibble::interval() masks lubridate::interval()
x dplyr::lag()        masks stats::lag()
# decompose(vaelsales_tbl_ts)
vaelsales_tbl_ts %>%
  model(STL(sales_GWh ~ trend(window=21) + season(window='periodic'), robust = TRUE)) %>%
  components() %>%
  autoplot()

vaelsales_tbl_ts %>%
  mutate(ln_sales_GWh = log(sales_GWh)) %>%
  model(STL(ln_sales_GWh ~ trend(window=21) + season(window='periodic'),
    robust = TRUE)) %>%
  components() %>%
  autoplot()

vaelsales_tbl_ts %>%
  features(sales_GWh, feat_stl)
vaelsales_tbl_ts %>%
  features(sales_GWh, feature_set(pkgs="feasts"))
Warning: `n_flat_spots()` is deprecated as of feasts 0.1.5.
Please use `longest_flat_spot()` instead.
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.

4 Example: Gross Domestic Product data

4.1 Exploratory data analysis

library(tsibbledata) # Data sets package

print(global_economy)
# A tsibble: 15,150 x 9 [1Y]
# Key:       Country [263]
   Country     Code   Year         GDP Growth   CPI Imports Exports Population
   <fct>       <fct> <dbl>       <dbl>  <dbl> <dbl>   <dbl>   <dbl>      <dbl>
 1 Afghanistan AFG    1960  537777811.     NA    NA    7.02    4.13    8996351
 2 Afghanistan AFG    1961  548888896.     NA    NA    8.10    4.45    9166764
 3 Afghanistan AFG    1962  546666678.     NA    NA    9.35    4.88    9345868
 4 Afghanistan AFG    1963  751111191.     NA    NA   16.9     9.17    9533954
 5 Afghanistan AFG    1964  800000044.     NA    NA   18.1     8.89    9731361
 6 Afghanistan AFG    1965 1006666638.     NA    NA   21.4    11.3     9938414
 7 Afghanistan AFG    1966 1399999967.     NA    NA   18.6     8.57   10152331
 8 Afghanistan AFG    1967 1673333418.     NA    NA   14.2     6.77   10372630
 9 Afghanistan AFG    1968 1373333367.     NA    NA   15.2     8.90   10604346
10 Afghanistan AFG    1969 1408888922.     NA    NA   15.0    10.1    10854428
# … with 15,140 more rows
global_economy %>% filter(Country=="Sweden") %>% print()
# A tsibble: 58 x 9 [1Y]
# Key:       Country [1]
   Country Code   Year          GDP Growth   CPI Imports Exports Population
   <fct>   <fct> <dbl>        <dbl>  <dbl> <dbl>   <dbl>   <dbl>      <dbl>
 1 Sweden  SWE    1960 14842870293.  NA     9.21    23.4    23.0    7484656
 2 Sweden  SWE    1961 16147160123.   5.68  9.41    21.7    22.3    7519998
 3 Sweden  SWE    1962 17511477311.   4.26  9.86    21.4    21.9    7561588
 4 Sweden  SWE    1963 18954132366.   5.33 10.1     21.5    21.9    7604328
 5 Sweden  SWE    1964 21137242561.   6.82 10.5     21.9    22.3    7661354
 6 Sweden  SWE    1965 23260320646.   3.82 11.0     22.5    21.9    7733853
 7 Sweden  SWE    1966 25302033132.   2.09 11.7     21.9    21.4    7807797
 8 Sweden  SWE    1967 27463409202.   3.37 12.2     21.0    21.1    7867931
 9 Sweden  SWE    1968 29143383491.   3.64 12.5     21.6    21.6    7912273
10 Sweden  SWE    1969 31649203886.   5.01 12.8     23.0    22.8    7968072
# … with 48 more rows
global_economy %>%
  filter(Country=="Sweden") %>%
  autoplot(GDP) +
  ggtitle("GDP for Sweden") + ylab("$US billions")

4.2 Fitting data to simple models

global_economy %>% model(trend_model = TSLM(GDP ~ trend())) -> fit
Warning: 7 errors (1 unique) encountered for trend_model
[7] 0 (non-NA) cases
fit
fit %>% filter(Country == "Sweden") %>% residuals()
fit %>% filter(Country == "Sweden") %>% residuals() %>% autoplot(.resid)

4.2.1 Work with ln(GDP)

global_economy %>%
  filter(Country=="Sweden") %>%
  autoplot(log(GDP)) +
  ggtitle("ln(GDP) for Sweden") + ylab("$US billions")

global_economy %>%
  model(trend_model = TSLM(log(GDP) ~ trend())) -> logfit
Warning: 7 errors (1 unique) encountered for trend_model
[7] 0 (non-NA) cases
logfit %>% filter(Country == "Sweden") %>% residuals() %>% autoplot()
Plot variable not specified, automatically selected `.vars = .resid`

global_economy %>% model(trend_model = TSLM(log(GDP) ~ log(Population))) -> fit3
Warning: 7 errors (1 unique) encountered for trend_model
[7] 0 (non-NA) cases
fit3 %>% filter(Country == "Sweden") %>% residuals() %>% autoplot()
Plot variable not specified, automatically selected `.vars = .resid`

5 Producing forecasts

fit %>% forecast(h = "3 years") -> fcast3yrs

fcast3yrs
fcast3yrs %>% filter(Country == "Sweden", Year == 2020) %>% str()
fable [1 × 5] (S3: fbl_ts/tbl_ts/tbl_df/tbl/data.frame)
 $ Country: Factor w/ 263 levels "Afghanistan",..: 232
 $ .model : chr "trend_model"
 $ Year   : num 2020
 $ GDP    : dist [1:1] 
  ..$ 3:List of 2
  .. ..$ mu   : num 5.45e+11
  .. ..$ sigma: num 5.34e+10
  .. ..- attr(*, "class")= chr [1:2] "dist_normal" "dist_default"
  ..@ vars: chr "GDP"
 $ .mean  : num 5.45e+11
 - attr(*, "key")= tibble [1 × 3] (S3: tbl_df/tbl/data.frame)
  ..$ Country: Factor w/ 263 levels "Afghanistan",..: 232
  ..$ .model : chr "trend_model"
  ..$ .rows  : list<int> [1:1] 
  .. ..$ : int 1
  .. ..@ ptype: int(0) 
  ..- attr(*, ".drop")= logi TRUE
 - attr(*, "index")= chr "Year"
  ..- attr(*, "ordered")= logi TRUE
 - attr(*, "index2")= chr "Year"
 - attr(*, "interval")= interval [1:1] 1Y
  ..@ .regular: logi TRUE
 - attr(*, "response")= chr "GDP"
 - attr(*, "dist")= chr "GDP"
 - attr(*, "model_cn")= chr ".model"
fcast3yrs %>% 
  filter(Country=="Sweden") %>%
  autoplot(global_economy) +
  ggtitle("GDP for Sweden") + ylab("$US billions")

5.1 Model residuals vs. forecast errors

Model residuals:

Your data: \(y_1, y_2, \ldots, y_T\)

Fitted values: \(\hat{y}_1, \hat{y}_2, \ldots, \hat{y}_T\)

Model residuals: \(e_t = y_t - \hat{y}_t\)

Forecast errors:

augment(fit)
augment(fit) %>% filter(Country == "Sweden") %>%
  ggplot(aes(x = .resid)) +
  geom_histogram(bins = 20) +
  ggtitle("Histogram of residuals")

5.2 Are the model residuals auto-correlated?

augment(fit) %>% filter(Country == "Sweden") -> augSweden

augSweden %>%
  ACF(.resid) %>%
  autoplot() + ggtitle("ACF of residuals")

augment(fit3) %>% filter(Country == "Sweden") -> augSweden3

augSweden3 %>%
  ACF(.resid) %>%
  autoplot() + ggtitle("ACF of residuals")

6 Statistical model

6.1 Formal model of data-generating process

Write down an equation (or set of equations) that represent the data-generating process formally.

For the electricity sales data, maybe the process looks like:

\[ y_t = Trend_t X Seasonal_t X Residual_t \] \[ y_t = \beta_0 + \beta_1 t + \beta_2 m + \varepsilon_t \]

# ETS forecasts
USAccDeaths %>%
  ets() %>%
  forecast() %>%
  autoplot()
str(taylor)
plot(taylor)

If applicable: describe any transformations of the data (e.g., differencing, taking logs) you need to make to get the data into a form (e.g., linear) ready for numerical analysis.

What kind of process is it? \(AR(p)\)? White noise with drift? Something else?

Write down an equation expressing each realization of the stochastic process \(y_t\) as a function of other observed data (which could include lagged values of \(y\)), unobserved parameters (\(\beta\)), and an error term (\(\varepsilon_t\)). Ex:

\[y = X\cdot\beta + \varepsilon\] Add a model of the error process. Ex: \(\varepsilon \sim N(0, \sigma^2 I_T)\).

6.2 Discussion of the statistical model

Describe how the formal statistical model captures and aligns with the narrative of the data-generating process. Flag any statistical challenges raised by the data generating process, e.g. selection bias; survivorship bias; omitted variables bias, etc.

7 Plan for data analysis

Describe what information you wish to extract from the data. Do you wish to… estimate the values of the unobserved model parameters? create a tool for forecasting? estimate the exceedance probabilities for future realizations of \(y_t\)?

Describe your plan for getting this information. OLS regression? Some other statistical technique?

If you can: describe briefly which computational tools you will use (e.g., R), and which packages you expect to draw on.

8 Submission requirements

Prepare your proposal using Markdown. (You may find it useful to generate your Markdown file from some other tool, e.g. R Markdown in R Studio.) Submit your proposal by pushing it to your repo within the course organization on Github. When your proposal is ready, notify the instructor by also creating a submission for this assignment on Collab. Please also upload a PDF version of your proposal to Collab as part of your submission.

9 Comment

Depending on your prior experience, you may find this assignment challenging. Treat this assignment as an opportunity to make progress on your own research program. Make your proposal as complete as you can. But note that this assignment is merely the First Draft. You will have more opportunity to refine your work over the next two months, in consultation with the instructor, your advisor, and your classmates.

10 References

National Research Council. 2007. Completing the Forecast: Characterizing and Communicating Uncertainty for Better Decisions Using Weather and Climate Forecasts. https://doi.org/10.17226/11699.

LS0tCnRpdGxlOiAgICAgIlByb2plY3QgUHJvcG9zYWwgSW5zdHJ1Y3Rpb25zIHdpdGggZXhhbXBsZSBjb2RlIgppbnN0aXR1dGU6ICJTWVMgNzAzMCBUaW1lIFNlcmllcyBBbmFseXNpcyAmIEZvcmVjYXN0aW5nLCBGYWxsIDIwMjAiIAphdXRob3I6ICAgICAiSW5zdHJ1Y3RvcjogQXJ0aHVyIFNtYWxsIgpkYXRlOiAgICAgICAiVmVyc2lvbiBvZiBgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogICAjIHBkZl9kb2N1bWVudDoKICAgIyAgIHRvYzogZmFsc2UKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBjb2RlX2ZvbGRpbmc6IHNob3cgIyBvcHRpb25zOiBzaG93LCBoaWRlCiAgICBmaWdfY2FwdGlvbjogeWVzCiAgaHRtbF9kb2N1bWVudDoKICAgICAgICBrZWVwX21kOiB5ZXMKICAjIHBkZl9kb2N1bWVudDogZGVmYXVsdApiaWJsaW9ncmFwaHk6IC9Vc2Vycy9BcnRodXIvR2l0UmVwb3MvVGVhY2hpbmcvdGltZS1zZXJpZXMvdHNlcmllcy5iaWIKbGluay1jaXRhdGlvbnM6IHllcwotLS0KCkluIHRoaXMgYXNzaWdubWVudCB5b3Ugd2lsbCBkZXZlbG9wIHlvdXIgaW5pdGlhbCBjb25jZXB0IG5vdGUgaW50byBhIGRyYWZ0IG9mIGEgZnVsbCBwcm9qZWN0IHByb3Bvc2FsLiBUcmVhdCB0aGlzIGFzc2lnbm1lbnQgYXMgYSAiZHJ5IHJ1biIgZm9yIGRldmVsb3BpbmcgYSBwcm9wb3NhbCBmb3IgYSBncmFudCBvciBmZWxsb3dzaGlwIGFwcGxpY2F0aW9uLCBvciBmb3IgeW91ciBQaC5ELiBwcm9zcGVjdHVzLgoKWW91ciBwcm9wb3NhbCBzaG91bGQgaW5jbHVkZSBhdCBsZWFzdCB0aGUgZm9sbG93aW5nIHNlY3Rpb25zIGFuZCBpbmZvcm1hdGlvbi4KCioqRnJvbnQgbWF0dGVyOioqIERlc2NyaXB0aXZlIHRpdGxlLCB5b3VyIG5hbWUsIGRhdGUsIHJlZmVyZW5jZSB0byAiU1lTIDcwMzAgVGltZSBTZXJpZXMgQW5hbHlzaXMgJiBGb3JlY2FzdGluZywgRmFsbCAyMDIwIi4KCioqQWJzdHJhY3Q6KiogQSB2ZXJ5IGJyaWVmIHN1bW1hcnkgb2YgdGhlIHByb2plY3QuCgojIEludHJvZHVjdGlvbgoKR2l2ZSBhIG5hcnJhdGl2ZSBkZXNjcmlwdGlvbiBvZiB0aGUgcHJvYmxlbSB5b3UgYXJlIGFkZHJlc3NpbmcsIGFuZCB0aGUgbWV0aG9kcyB5b3Ugd2lsbCB1c2UgdG8gYWRkcmVzcyBpdC4gUHJvdmlkZSBjb250ZXh0OgoKLSAgIFdoYXQgaXMgdGhlIHF1ZXN0aW9uIHlvdSBhcmUgYXR0ZW1wdGluZyB0byBhbnN3ZXI/Ci0gICBXaHkgaXMgdGhpcyBxdWVzdGlvbiBpbXBvcnRhbnQ/IChXaG8gY2FyZXM/KQotICAgSG93IHdpbGwgeW91IGdvIGFib3V0IGF0dGVtcHRpbmcgdG8gYW5zd2VyIHRoaXMgcXVlc3Rpb24/CgpUaGlzIHdvcmsgYWRkcmVzc2VzIHRoZSBxdWVzdGlvbjogV2h5IGRvIHBlb3BsZSBub3QgdXNlIHByb2JhYmlsaXN0aWMgZm9yZWNhc3RzIGZvciBkZWNpc2lvbi1tYWtpbmcgW0Bjb3VuY2lsQ29tcGxldGluZ0ZvcmVjYXN0Q2hhcmFjdGVyaXppbmcyMDA3XT8KCiMgVGhlIGRhdGEgYW5kIHRoZSBkYXRhLWdlbmVyYXRpbmcgcHJvY2VzcwoKRGVzY3JpYmUgdGhlIGRhdGEgc2V0IHlvdSB3aWxsIGJlIGFuYWx5emluZywgYW5kIHdoZXJlIGl0IGNvbWVzIGZyb20sIGhvdyBpdCB3YXMgZ2VuZXJhdGVkIGFuZCBjb2xsZWN0ZWQuIElkZW50aWZ5IHRoZSBzb3VyY2Ugb2YgdGhlIGRhdGEuIEdpdmUgYSBuYXJyYXRpdmUgZGVzY3JpcHRpb24gb2YgdGhlIGRhdGEtZ2VuZXJhdGluZyBwcm9jZXNzOiB0aGlzIHBpZWNlIGlzIGNyaXRpY2FsLgoKU2luY2UgdGhlc2Ugd2lsbCBiZSB0aW1lIHNlcmllcyBkYXRhOiBpZGVudGlmeSB0aGUgZnJlcXVlbmN5IG9mIHRoZSBkYXRhIHNlcmllcyAoZS5nLiwgaG91cmx5LCBtb250aGx5KSwgYW5kIHRoZSBwZXJpb2Qgb2YgcmVjb3JkLgoKYGBge3Igc2V0IHVwIGNvZGluZyBlbnZpcm9ubWVudCwgaW5jbHVkZT1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBsaWJyYXJ5KGRwbHlyKSAtLSBkb24ndCBuZWVkIHRoaXMgaWYgeW91IGFyZSBsb2FkaW5nIHRoZSBlbnRpcmUgJ3RpZHl2ZXJzZScgc3VpdGUKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobHVicmlkYXRlKSAjIEZvciBlYXN5IGhhbmRsaW5nIG9mIHRpbWUtaW5kZXhlZCBvYmplY3RzCmBgYAoKYGBge3Igb3BlbiBjb25uZWN0aW9uIHRvIGRhdGFiYXNlLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQojIE9wZW4gY29ubmVjdGlvbiB0byBhIHJlbW90ZSBkYXRhYmFzZQojIE1ha2Ugc3VyZSB5b3VyIFZQTiBuZXR3b3JrIGNvbm5lY3Rpb24gaXMgYWN0aXZlIGlmIG5lZWRlZCEKCiMgaWYoISgnUlBvc3RncmVTUUwnICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkpKSBpbnN0YWxsLnBhY2thZ2VzKCdSUG9zdGdyZVNRTCcpCmxpYnJhcnkoUlBvc3RncmVTUUwpCgojICJteV9wb3N0Z3Jlc19jcmVkZW50aWFscy5SIiBjb250YWlucyB0aGUgbG9nLWluIGluZm9ybWF0aW9uCnNvdXJjZSgiL1VzZXJzL0FydGh1ci9HaXRSZXBvcy9UZWFjaGluZy9teV9wb3N0Z3Jlc19kYl9jcmVkZW50aWFscy5SIikKCiMgT3BlbiBjb25uZWN0aW9uCmRiX2RyaXZlciA8LSBkYkRyaXZlcigiUG9zdGdyZVNRTCIpCmRiIDwtIGRiQ29ubmVjdChkYl9kcml2ZXIsdXNlcj11c2VyLCBwYXNzd29yZD1wYXNzd29yZCxkYm5hbWU9InBvc3RncmVzIiwgaG9zdD1ob3N0KQpybShwYXNzd29yZCkgCgojIGNoZWNrIHRoZSBjb25uZWN0aW9uOiBJZiBmdW5jdGlvbiByZXR1cm5zIHZhbHVlIFRSVUUsIHRoZSBjb25uZWN0aW9uIGlzIHdvcmtpbmcKZGJFeGlzdHNUYWJsZShkYiwgIm1ldGFkYXRhIikKYGBgCgpgYGB7ciByZXRyaWV2ZSBkYXRhIGZyb20gZGIsIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9Cgplc2FsZXMgPC0gZGJHZXRRdWVyeShkYiwnU0VMRUNUICogZnJvbSBlaWFfZWxlY19zYWxlc192YV9hbGxfbScpICMgU1FMIGNvZGUgdG8gcmV0cmlldmUgZGF0YSBmcm9tIGEgdGFibGUgaW4gdGhlIHJlbW90ZSBkYXRhYmFzZQojIHN0cihlc2FsZXMpCmVzYWxlcyA8LSBhc190aWJibGUoZXNhbGVzKSAjIENvbnZlcnQgZGF0YWZyYW1lIHRvIGEgJ3RpYmJsZScgZm9yIHRpZHl2ZXJzZSB3b3JrCiMgc3RyKGVzYWxlcykKYGBgCgpgYGB7ciBzYXZlIGRhdGEgaW4gQXBhY2hlIEFycm93IGZvcm1hdCwgZXZhbD1GQUxTRX0KIyBSZWZlcmVuY2U6IGh0dHBzOi8vYXJyb3cuYXBhY2hlLm9yZy9kb2NzL3IvCiMgaWYoISgnYXJyb3cnICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkpKSBpbnN0YWxsLnBhY2thZ2VzKCdhcnJvdycpCmxpYnJhcnkoYXJyb3cpCndyaXRlX2ZlYXRoZXIoZXNhbGVzLCAiZXNhbGVzLmZlYXRoZXIiKQpgYGAKCmBgYHtyIGNsb3NlIGRiIGNvbm5lY3Rpb24sIGV2YWw9RkFMU0V9CiMgQ2xvc2UgY29ubmVjdGlvbiAtLSB0aGlzIGlzIGdvb2QgcHJhY3RpY2UKZGJEaXNjb25uZWN0KGRiKQpkYlVubG9hZERyaXZlcihkYl9kcml2ZXIpCmBgYAoKIyBFeHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzCgpgYGB7ciByZWFkIGluIGRhdGF9CmxpYnJhcnkoYXJyb3cpCmVzYWxlcyA8LSByZWFkX2ZlYXRoZXIoImVzYWxlcy5mZWF0aGVyIikKCnN0cihlc2FsZXMpCmBgYAoKIyMgUHJvdmlkZSBhIGJyaWVmIGV4YW1wbGUgb2YgdGhlIGRhdGEsIHNob3dpbmcgaG93IHRoZXkgYXJlIHN0cnVjdHVyZWQuCgpgYGB7ciBwcmludCB0aGUgZGF0YSBhcyBhIHRhYmxlfQpwcmludChlc2FsZXMpCmBgYAoKYGBge3IgdXNlIHRpZHl2ZXJzZSBzeW50YXggdG8gcGVyZm9ybSBzb21lIHNpbXBsZSBkYXRhIG1hbmlwdWxhdGlvbnN9CiMgUmVmZXJlbmNlczogaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8sIGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy8KCmVzYWxlcyAlPiUKICBmaWx0ZXIoeWVhciA9PSAyMDE5KSAlPiUKICBmaWx0ZXIodmFsdWUgPiA5MDAwKSAlPiUKICBwcmludCgpCgplc2FsZXMgJT4lCiAgZ3JvdXBfYnkobW9udGgpICU+JQogIHN1bW1hcmlzZShtZWFuID0gbWVhbih2YWx1ZSkpIC0+IG1lYW5fZXNhbGVzX2J5X21vbnRoCgplc2FsZXMgJT4lCiAgbXV0YXRlKHNhbGVzX1RXaCA9IHZhbHVlLzEwMDApICU+JQogIHNlbGVjdCgtdmFsdWUpCiAgCiMgZmlsdGVyKGRhdGEgb2JqZWN0LCBjb25kaXRpb24pIDogc3ludGF4IGZvciBmaWx0ZXIoKSBjb21tYW5kCmBgYAoKIyMgUGxvdCB0aGUgdGltZSBzZXJpZXMuCgpgYGB7ciB1c2UgZ2dwbG90MiB0byBnZW5lcmF0ZSBhIHBsb3R9CiNSZWZlcmVuY2U6IGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLwoKZ2dwbG90KGRhdGE9ZXNhbGVzLCBhZXMoeD1kYXRlLHk9dmFsdWUpKSArIAogIGdlb21fbGluZSgpICsgeGxhYigiWWVhciIpICsgeWxhYigiVmlyZ2luaWEgbW9udGhseSB0b3RhbCBlbGVjdHJpY2l0eSBzYWxlcyAoR1doKSIpCgpgYGAKCgoKCmBgYHtyfQojIGluc3RhbGwucGFja2FnZXMoInRzaWJibGUiKQpsaWJyYXJ5KHRzaWJibGUpICMgUmVmZXJlbmNlOiBodHRwczovL3RzaWJibGUudGlkeXZlcnRzLm9yZy9hcnRpY2xlcy9pbnRyby10c2liYmxlLmh0bWwKCmVzYWxlcyAlPiUgYXNfdHNpYmJsZShpbmRleCA9IGRhdGUpIC0+IGVzYWxlc190YmxfdHMKCnByaW50KGVzYWxlc190YmxfdHMpCmBgYAoKYGBge3J9CmxpYnJhcnkobHVicmlkYXRlKSAjIE1ha2UgaXQgZWFzeSB0byBkZWFsIHdpdGggZGF0ZXMKCmVzYWxlc190YmxfdHMgJT4lIGZpbHRlcihtb250aD09MykKCmVzYWxlc190YmxfdHMgJT4lIGZpbHRlcihtb250aChkYXRlKT09MykKCmVzYWxlc190YmxfdHMgJT4lCiAgc2VsZWN0KGRhdGUsIHNhbGVzX0dXaCA9IHZhbHVlKSAtPiBlbHNhbGVzX3RibF90cwoKcHJpbnQoZWxzYWxlc190YmxfdHMpCmBgYAoKCgoKIyMgUGVyZm9ybSBhbmQgcmVwb3J0IHRoZSByZXN1bHRzIG9mIG90aGVyIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMKCgpgYGB7ciBtYWtlIGEgaGlzdG9ncmFtIG9mIHRoZSBkYXRhfQoKaGlzdChlbHNhbGVzX3RibF90cyRzYWxlc19HV2gsIGJyZWFrcz00MCkKYGBgCgoKYGBge3J9CiMgaW5zdGFsbC5wYWNrYWdlcygiZmVhc3RzIiksIFJlZmVyZW5jZTogaHR0cHM6Ly9mZWFzdHMudGlkeXZlcnRzLm9yZy8KbGlicmFyeShmZWFzdHMpCgplbHNhbGVzX3RibF90cyAlPiUgCiAgbXV0YXRlKE1vbnRoID0geWVhcm1vbnRoKGRhdGUpKSAlPiUgCiAgYXNfdHNpYmJsZShpbmRleCA9IE1vbnRoKSAtPiB2YWVsc2FsZXNfdGJsX3RzCgoKdmFlbHNhbGVzX3RibF90cyAlPiUgZ2dfc2Vhc29uKHNhbGVzX0dXaCwgbGFiZWxzID0gImJvdGgiKSArIHlsYWIoIlZpcmdpbmlhIGVsZWN0cmljaXR5IHNhbGVzIChHV2gpIikKYGBgCgpgYGB7cn0KIyBpbnN0YWxsLnBhY2thZ2VzKCd0c2liYmxlZGF0YScpCmxpYnJhcnkodHNpYmJsZWRhdGEpCgphdXNfcHJvZHVjdGlvbgoKYXVzX3Byb2R1Y3Rpb24gJT4lIGdnX3NlYXNvbihFbGVjdHJpY2l0eSkKCmF1c19wcm9kdWN0aW9uICU+JSBnZ19zZWFzb24oQmVlcikKCgpgYGAKYGBge3J9CnZhZWxzYWxlc190YmxfdHMgJT4lIAogIGdnX3N1YnNlcmllcyhzYWxlc19HV2gpCgojIGF1c19wcm9kdWN0aW9uICU+JSBnZ19zdWJzZXJpZXMoQmVlcikKYGBgCgpgYGB7ciBwbG90IGxhZ2dlZCB2YWx1ZXN9CnZhZWxzYWxlc190YmxfdHMgICU+JSBmaWx0ZXIobW9udGgoTW9udGgpICVpbiUgYygzLDYsOSwxMikpICU+JSBnZ19sYWcoc2FsZXNfR1doLCBsYWdzID0gMToyKQoKdmFlbHNhbGVzX3RibF90cyAgJT4lIGZpbHRlcihtb250aChNb250aCkgPT0gMSkgJT4lIGdnX2xhZyhzYWxlc19HV2gsIGxhZ3MgPSAxOjIpCmBgYAoKYGBge3J9CnZhZWxzYWxlc190YmxfdHMgJT4lIEFDRihzYWxlc19HV2gpICU+JSBhdXRvcGxvdCgpCmBgYAoKYGBge3IgcGVyZm9ybSBhdXRvbWF0ZWQgdGltZSBzZXJpZXMgZGVjb21wb3NpdGlvbn0KIyBpZighKCdmcHAzJyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpKSkgaW5zdGFsbC5wYWNrYWdlcygnZnBwMycpCmxpYnJhcnkoZnBwMykKCiMgZGVjb21wb3NlKHZhZWxzYWxlc190YmxfdHMpCmBgYAoKCmBgYHtyIHBlcmZvcm0gYWRkaXRpdmUgU1RMIGRlY29tcG9zaXRpb24gb2YgdGhlIFZBIGVsZWN0cmljaXR5IHNhbGVzIHRpbWUgc2VyaWVzfQp2YWVsc2FsZXNfdGJsX3RzICU+JQogIG1vZGVsKFNUTChzYWxlc19HV2ggfiB0cmVuZCh3aW5kb3c9MjEpICsgc2Vhc29uKHdpbmRvdz0ncGVyaW9kaWMnKSwgcm9idXN0ID0gVFJVRSkpICU+JQogIGNvbXBvbmVudHMoKSAlPiUKICBhdXRvcGxvdCgpCmBgYAoKYGBge3IgcGVyZm9ybSBtdWx0aXBsaWNhdGl2ZSBTVEwgZGVjb21wb3NpdGlvbiBvZiB0aGUgVkEgZWxlY3RyaWNpdHkgc2FsZXMgdGltZSBzZXJpZXN9CnZhZWxzYWxlc190YmxfdHMgJT4lCiAgbXV0YXRlKGxuX3NhbGVzX0dXaCA9IGxvZyhzYWxlc19HV2gpKSAlPiUKICBtb2RlbChTVEwobG5fc2FsZXNfR1doIH4gdHJlbmQod2luZG93PTIxKSArIHNlYXNvbih3aW5kb3c9J3BlcmlvZGljJyksCiAgICByb2J1c3QgPSBUUlVFKSkgJT4lCiAgY29tcG9uZW50cygpICU+JQogIGF1dG9wbG90KCkKYGBgCmBgYHtyfQp2YWVsc2FsZXNfdGJsX3RzICU+JQogIGZlYXR1cmVzKHNhbGVzX0dXaCwgZmVhdF9zdGwpCmBgYApgYGB7cn0KdmFlbHNhbGVzX3RibF90cyAlPiUKICBmZWF0dXJlcyhzYWxlc19HV2gsIGZlYXR1cmVfc2V0KHBrZ3M9ImZlYXN0cyIpKQpgYGAKCiMgRXhhbXBsZTogR3Jvc3MgRG9tZXN0aWMgUHJvZHVjdCBkYXRhIAoKIyMgRXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcwoKYGBge3J9CmxpYnJhcnkodHNpYmJsZWRhdGEpICMgRGF0YSBzZXRzIHBhY2thZ2UKCnByaW50KGdsb2JhbF9lY29ub215KQpgYGAKCgpgYGB7cn0KZ2xvYmFsX2Vjb25vbXkgJT4lIGZpbHRlcihDb3VudHJ5PT0iU3dlZGVuIikgJT4lIHByaW50KCkKYGBgCgoKYGBge3J9Cmdsb2JhbF9lY29ub215ICU+JQogIGZpbHRlcihDb3VudHJ5PT0iU3dlZGVuIikgJT4lCiAgYXV0b3Bsb3QoR0RQKSArCiAgZ2d0aXRsZSgiR0RQIGZvciBTd2VkZW4iKSArIHlsYWIoIiRVUyBiaWxsaW9ucyIpCmBgYAoKIyMgRml0dGluZyBkYXRhIHRvIHNpbXBsZSBtb2RlbHMKCgpgYGB7cn0KZ2xvYmFsX2Vjb25vbXkgJT4lIG1vZGVsKHRyZW5kX21vZGVsID0gVFNMTShHRFAgfiB0cmVuZCgpKSkgLT4gZml0CgpmaXQKCgpgYGAKCgpgYGB7cn0KZml0ICU+JSBmaWx0ZXIoQ291bnRyeSA9PSAiU3dlZGVuIikgJT4lIHJlc2lkdWFscygpCmBgYApgYGB7cn0KCmZpdCAlPiUgZmlsdGVyKENvdW50cnkgPT0gIlN3ZWRlbiIpICU+JSByZXNpZHVhbHMoKSAlPiUgYXV0b3Bsb3QoLnJlc2lkKQpgYGAKIyMjIFdvcmsgd2l0aCBsbihHRFApCgpgYGB7cn0KZ2xvYmFsX2Vjb25vbXkgJT4lCiAgZmlsdGVyKENvdW50cnk9PSJTd2VkZW4iKSAlPiUKICBhdXRvcGxvdChsb2coR0RQKSkgKwogIGdndGl0bGUoImxuKEdEUCkgZm9yIFN3ZWRlbiIpICsgeWxhYigiJFVTIGJpbGxpb25zIikKYGBgCgpgYGB7cn0KZ2xvYmFsX2Vjb25vbXkgJT4lCiAgbW9kZWwodHJlbmRfbW9kZWwgPSBUU0xNKGxvZyhHRFApIH4gdHJlbmQoKSkpIC0+IGxvZ2ZpdApgYGAKCmBgYHtyfQpsb2dmaXQgJT4lIGZpbHRlcihDb3VudHJ5ID09ICJTd2VkZW4iKSAlPiUgcmVzaWR1YWxzKCkgJT4lIGF1dG9wbG90KCkKYGBgCgoKCmBgYHtyfQpnbG9iYWxfZWNvbm9teSAlPiUgbW9kZWwodHJlbmRfbW9kZWwgPSBUU0xNKGxvZyhHRFApIH4gbG9nKFBvcHVsYXRpb24pKSkgLT4gZml0MwoKZml0MyAlPiUgZmlsdGVyKENvdW50cnkgPT0gIlN3ZWRlbiIpICU+JSByZXNpZHVhbHMoKSAlPiUgYXV0b3Bsb3QoKQoKYGBgCiMgUHJvZHVjaW5nIGZvcmVjYXN0cwoKCmBgYHtyfQpmaXQgJT4lIGZvcmVjYXN0KGggPSAiMyB5ZWFycyIpIC0+IGZjYXN0M3lycwoKZmNhc3QzeXJzCgpgYGAKYGBge3J9CgpmY2FzdDN5cnMgJT4lIGZpbHRlcihDb3VudHJ5ID09ICJTd2VkZW4iLCBZZWFyID09IDIwMjApICU+JSBzdHIoKQpgYGAKCgpgYGB7ciB2aXN1YWxpemUgZm9yZWNhc3RzfQpmY2FzdDN5cnMgJT4lIAogIGZpbHRlcihDb3VudHJ5PT0iU3dlZGVuIikgJT4lCiAgYXV0b3Bsb3QoZ2xvYmFsX2Vjb25vbXkpICsKICBnZ3RpdGxlKCJHRFAgZm9yIFN3ZWRlbiIpICsgeWxhYigiJFVTIGJpbGxpb25zIikKYGBgCgojIyBNb2RlbCByZXNpZHVhbHMgdnMuIGZvcmVjYXN0IGVycm9ycwoKTW9kZWwgcmVzaWR1YWxzOgoKWW91ciBkYXRhOiAkeV8xLCB5XzIsIFxsZG90cywgeV9UJAoKRml0dGVkIHZhbHVlczogJFxoYXR7eX1fMSwgXGhhdHt5fV8yLCBcbGRvdHMsIFxoYXR7eX1fVCQKCgpNb2RlbCByZXNpZHVhbHM6ICRlX3QgPSB5X3QgLSBcaGF0e3l9X3QkCgpGb3JlY2FzdCBlcnJvcnM6CgpgYGB7cn0KYXVnbWVudChmaXQpCmBgYAoKYGBge3J9CmF1Z21lbnQoZml0KSAlPiUgZmlsdGVyKENvdW50cnkgPT0gIlN3ZWRlbiIpICU+JQogIGdncGxvdChhZXMoeCA9IC5yZXNpZCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjApICsKICBnZ3RpdGxlKCJIaXN0b2dyYW0gb2YgcmVzaWR1YWxzIikKYGBgCgojIyBBcmUgdGhlIG1vZGVsIHJlc2lkdWFscyBhdXRvLWNvcnJlbGF0ZWQ/CgpgYGB7cn0KYXVnbWVudChmaXQpICU+JSBmaWx0ZXIoQ291bnRyeSA9PSAiU3dlZGVuIikgLT4gYXVnU3dlZGVuCgphdWdTd2VkZW4gJT4lCiAgQUNGKC5yZXNpZCkgJT4lCiAgYXV0b3Bsb3QoKSArIGdndGl0bGUoIkFDRiBvZiByZXNpZHVhbHMiKQpgYGAKYGBge3J9CmF1Z21lbnQoZml0MykgJT4lIGZpbHRlcihDb3VudHJ5ID09ICJTd2VkZW4iKSAtPiBhdWdTd2VkZW4zCgphdWdTd2VkZW4zICU+JQogIEFDRigucmVzaWQpICU+JQogIGF1dG9wbG90KCkgKyBnZ3RpdGxlKCJBQ0Ygb2YgcmVzaWR1YWxzIikKYGBgCgoKIyBTdGF0aXN0aWNhbCBtb2RlbAoKIyMgRm9ybWFsIG1vZGVsIG9mIGRhdGEtZ2VuZXJhdGluZyBwcm9jZXNzCgpXcml0ZSBkb3duIGFuIGVxdWF0aW9uIChvciBzZXQgb2YgZXF1YXRpb25zKSB0aGF0IHJlcHJlc2VudCB0aGUgZGF0YS1nZW5lcmF0aW5nIHByb2Nlc3MgZm9ybWFsbHkuCgpGb3IgdGhlIGVsZWN0cmljaXR5IHNhbGVzIGRhdGEsIG1heWJlIHRoZSBwcm9jZXNzIGxvb2tzIGxpa2U6CgokJCB5X3QgPSBUcmVuZF90IFggU2Vhc29uYWxfdCBYIFJlc2lkdWFsX3QgJCQKJCQgeV90ID0gXGJldGFfMCArIFxiZXRhXzEgdCArIFxiZXRhXzIgbSArIFx2YXJlcHNpbG9uX3QgJCQKCgoKCgoKYGBge3IsIGV2YWw9RkFMU0V9CiMgRVRTIGZvcmVjYXN0cwpVU0FjY0RlYXRocyAlPiUKICBldHMoKSAlPiUKICBmb3JlY2FzdCgpICU+JQogIGF1dG9wbG90KCkKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0Kc3RyKHRheWxvcikKcGxvdCh0YXlsb3IpCmBgYAoKCgpJZiBhcHBsaWNhYmxlOiBkZXNjcmliZSBhbnkgdHJhbnNmb3JtYXRpb25zIG9mIHRoZSBkYXRhIChlLmcuLCBkaWZmZXJlbmNpbmcsIHRha2luZyBsb2dzKSB5b3UgbmVlZCB0byBtYWtlIHRvIGdldCB0aGUgZGF0YSBpbnRvIGEgZm9ybSAoZS5nLiwgbGluZWFyKSByZWFkeSBmb3IgbnVtZXJpY2FsIGFuYWx5c2lzLgoKV2hhdCBraW5kIG9mIHByb2Nlc3MgaXMgaXQ/ICRBUihwKSQ/IFdoaXRlIG5vaXNlIHdpdGggZHJpZnQ/IFNvbWV0aGluZyBlbHNlPwoKV3JpdGUgZG93biBhbiBlcXVhdGlvbiBleHByZXNzaW5nIGVhY2ggcmVhbGl6YXRpb24gb2YgdGhlIHN0b2NoYXN0aWMgcHJvY2VzcyAkeV90JCBhcyBhIGZ1bmN0aW9uIG9mIG90aGVyIG9ic2VydmVkIGRhdGEgKHdoaWNoIGNvdWxkIGluY2x1ZGUgbGFnZ2VkIHZhbHVlcyBvZiAkeSQpLCB1bm9ic2VydmVkIHBhcmFtZXRlcnMgKCRcYmV0YSQpLCBhbmQgYW4gZXJyb3IgdGVybSAoJFx2YXJlcHNpbG9uX3QkKS4gRXg6CgokJHkgPSBYXGNkb3RcYmV0YSArIFx2YXJlcHNpbG9uJCQgQWRkIGEgbW9kZWwgb2YgdGhlIGVycm9yIHByb2Nlc3MuIEV4OiAkXHZhcmVwc2lsb24gXHNpbSBOKDAsIFxzaWdtYV4yIElfVCkkLgoKIyMgRGlzY3Vzc2lvbiBvZiB0aGUgc3RhdGlzdGljYWwgbW9kZWwKCkRlc2NyaWJlIGhvdyB0aGUgZm9ybWFsIHN0YXRpc3RpY2FsIG1vZGVsIGNhcHR1cmVzIGFuZCBhbGlnbnMgd2l0aCB0aGUgbmFycmF0aXZlIG9mIHRoZSBkYXRhLWdlbmVyYXRpbmcgcHJvY2Vzcy4gRmxhZyBhbnkgc3RhdGlzdGljYWwgY2hhbGxlbmdlcyByYWlzZWQgYnkgdGhlIGRhdGEgZ2VuZXJhdGluZyBwcm9jZXNzLCBlLmcuIHNlbGVjdGlvbiBiaWFzOyBzdXJ2aXZvcnNoaXAgYmlhczsgb21pdHRlZCB2YXJpYWJsZXMgYmlhcywgZXRjLgoKIyBQbGFuIGZvciBkYXRhIGFuYWx5c2lzCgpEZXNjcmliZSB3aGF0IGluZm9ybWF0aW9uIHlvdSB3aXNoIHRvIGV4dHJhY3QgZnJvbSB0aGUgZGF0YS4gRG8geW91IHdpc2ggdG8uLi4gZXN0aW1hdGUgdGhlIHZhbHVlcyBvZiB0aGUgdW5vYnNlcnZlZCBtb2RlbCBwYXJhbWV0ZXJzPyBjcmVhdGUgYSB0b29sIGZvciBmb3JlY2FzdGluZz8gZXN0aW1hdGUgdGhlIGV4Y2VlZGFuY2UgcHJvYmFiaWxpdGllcyBmb3IgZnV0dXJlIHJlYWxpemF0aW9ucyBvZiAkeV90JD8KCkRlc2NyaWJlIHlvdXIgcGxhbiBmb3IgZ2V0dGluZyB0aGlzIGluZm9ybWF0aW9uLiBPTFMgcmVncmVzc2lvbj8gU29tZSBvdGhlciBzdGF0aXN0aWNhbCB0ZWNobmlxdWU/CgpJZiB5b3UgY2FuOiBkZXNjcmliZSBicmllZmx5IHdoaWNoIGNvbXB1dGF0aW9uYWwgdG9vbHMgeW91IHdpbGwgdXNlIChlLmcuLCBSKSwgYW5kIHdoaWNoIHBhY2thZ2VzIHlvdSBleHBlY3QgdG8gZHJhdyBvbi4KCiMgU3VibWlzc2lvbiByZXF1aXJlbWVudHMKClByZXBhcmUgeW91ciBwcm9wb3NhbCB1c2luZyBNYXJrZG93bi4gKFlvdSBtYXkgZmluZCBpdCB1c2VmdWwgdG8gZ2VuZXJhdGUgeW91ciBNYXJrZG93biBmaWxlIGZyb20gc29tZSBvdGhlciB0b29sLCBlLmcuIFIgTWFya2Rvd24gaW4gUiBTdHVkaW8uKSBTdWJtaXQgeW91ciBwcm9wb3NhbCBieSBwdXNoaW5nIGl0IHRvIHlvdXIgcmVwbyB3aXRoaW4gdGhlIGNvdXJzZSBvcmdhbml6YXRpb24gb24gR2l0aHViLiBXaGVuIHlvdXIgcHJvcG9zYWwgaXMgcmVhZHksIG5vdGlmeSB0aGUgaW5zdHJ1Y3RvciBieSBhbHNvIGNyZWF0aW5nIGEgc3VibWlzc2lvbiBmb3IgdGhpcyBhc3NpZ25tZW50IG9uIENvbGxhYi4gUGxlYXNlIGFsc28gdXBsb2FkIGEgUERGIHZlcnNpb24gb2YgeW91ciBwcm9wb3NhbCB0byBDb2xsYWIgYXMgcGFydCBvZiB5b3VyIHN1Ym1pc3Npb24uCgojIENvbW1lbnQKCkRlcGVuZGluZyBvbiB5b3VyIHByaW9yIGV4cGVyaWVuY2UsIHlvdSBtYXkgZmluZCB0aGlzIGFzc2lnbm1lbnQgY2hhbGxlbmdpbmcuIFRyZWF0IHRoaXMgYXNzaWdubWVudCBhcyBhbiBvcHBvcnR1bml0eSB0byBtYWtlIHByb2dyZXNzIG9uIHlvdXIgb3duIHJlc2VhcmNoIHByb2dyYW0uIE1ha2UgeW91ciBwcm9wb3NhbCBhcyBjb21wbGV0ZSBhcyB5b3UgY2FuLiBCdXQgbm90ZSB0aGF0IHRoaXMgYXNzaWdubWVudCBpcyBtZXJlbHkgdGhlIEZpcnN0IERyYWZ0LiBZb3Ugd2lsbCBoYXZlIG1vcmUgb3Bwb3J0dW5pdHkgdG8gcmVmaW5lIHlvdXIgd29yayBvdmVyIHRoZSBuZXh0IHR3byBtb250aHMsIGluIGNvbnN1bHRhdGlvbiB3aXRoIHRoZSBpbnN0cnVjdG9yLCB5b3VyIGFkdmlzb3IsIGFuZCB5b3VyIGNsYXNzbWF0ZXMuCgojIFJlZmVyZW5jZXMK